package com.cxl.harmony.clickgame.slice;

import com.cxl.harmony.clickgame.ResourceTable;
import com.cxl.harmony.clickgame.utils.CommonData;
import com.cxl.harmony.clickgame.utils.LogUtil;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.ability.IAbilityConnection;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.Text;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.window.dialog.ToastDialog;
import ohos.app.Context;
import ohos.bundle.ElementName;
import ohos.event.commonevent.*;
import ohos.rpc.*;

import java.util.Timer;
import java.util.TimerTask;

public class ClickGameSlice extends AbilitySlice {
    private static final String TAG = CommonData.TAG + ClickGameSlice.class.getSimpleName();

    private IRemoteObject remoteObject;

    private MathRemoteProxy proxy;

    private Context context;

    private MyCommonEventSubscriber subscriber;

    private boolean isLocal;

    private int myclickNum = 0;
    private int otherClickNum = 0;

    private Text remainTimeText;
    private Text myClickNumText;
    private Text otherClickNumText;
    private Text resultMsgText;
    private Button clickBtn;
    private Button startBtn;

    private Timer timer;
    private TimerTask timerTask;
    private static int MAX_TIME = 20;
    private int currentTime = MAX_TIME;

    //1:开始 2:结束
    private int status = 0;
    //对方有没有结束
    private boolean otherEnd;
    //我方有没有结束
    private boolean meEnd;
    //pa是否连接成功
    private boolean hasPaConnectDone;

    @Override
    public void onStart(Intent intent) {
        LogUtil.info(TAG, "onStart");
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_clickgame);
        initAndConnectDevice(intent);
        initView();
        subscribe();
    }

    private void initView() {
        remainTimeText = (Text) findComponentById(ResourceTable.Id_remain_time);
        myClickNumText = (Text) findComponentById(ResourceTable.Id_my_click_num);
        otherClickNumText = (Text) findComponentById(ResourceTable.Id_other_click_num);
        resultMsgText = (Text) findComponentById(ResourceTable.Id_result_msg);
        clickBtn = (Button) findComponentById(ResourceTable.Id_click_btn);
        startBtn = (Button) findComponentById(ResourceTable.Id_start_btn);
        if (isLocal) {
            startBtn.setVisibility(Component.VISIBLE);
        } else {
            startBtn.setVisibility(Component.INVISIBLE);
        }

        clickBtn.setClickedListener(new ButtonClick());
        startBtn.setClickedListener(new ButtonClick());
    }

    private class ButtonClick implements Component.ClickedListener {
        @Override
        public void onClick(Component component) {
            int btnId = component.getId();
            switch (btnId) {
                case ResourceTable.Id_click_btn:
                    myclickNum++;
                    senDataToRemote();
                    break;
                case ResourceTable.Id_start_btn:
                    start();
                    break;
                default:
                    LogUtil.info(TAG, "Click default");
                    break;
            }
        }
    }

    private void startTimer() {
        stopTimer();
        if (timer == null) {
            timer = new Timer();
        }
        if (timerTask == null) {
            timerTask = new TimerTask() {
                @Override
                public void run() {
                    currentTime--;
                    showTime();
                    if (currentTime == 0) {
                        stopTimer();
                        meEnd = true;
                        status = 2;
                        hideClickBtn();
                        senDataToRemote();
                        checkShowResult();
                    }
                }
            };
        }
        timer.schedule(timerTask, 0, 1000);
    }

    private void stopTimer() {
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
        if (timerTask != null) {
            timerTask.cancel();
            timerTask = null;
        }
    }

    private void hideClickBtn() {
        //在主线程运行
        getUITaskDispatcher().asyncDispatch(new Runnable() {
            @Override
            public void run() {
                clickBtn.setVisibility(Component.INVISIBLE);
            }
        });
    }

    private void checkShowResult() {
        LogUtil.info("tag001", "checkShowResult#!meEnd:" + !meEnd + ",!otherEnd:" + !otherEnd);
        if (!meEnd || !otherEnd) {
            return;
        }
        //在主线程运行
        getUITaskDispatcher().asyncDispatch(new Runnable() {
            @Override
            public void run() {
                clickBtn.setVisibility(Component.INVISIBLE);
                if (myclickNum > otherClickNum) {
                    resultMsgText.setText("你赢了");
                } else if (myclickNum < otherClickNum) {
                    resultMsgText.setText("你输了");
                } else {
                    resultMsgText.setText("平局");
                }
            }
        });
    }

    private void showTime() {
        //在主线程运行
        getUITaskDispatcher().asyncDispatch(new Runnable() {
            @Override
            public void run() {
                remainTimeText.setText(currentTime + "");
            }
        });
    }

    private void start() {
        if (!hasPaConnectDone || CommonData.hasOtherConnectDone == false) {
            LogUtil.info("tag001", "正在连接中，请稍候...");
            showMessage("正在连接中，请稍候...");
            return;
        }
        meEnd = false;
        myclickNum = 0;
        otherClickNum = 0;
        currentTime = MAX_TIME;
        status = 1;
        clickBtn.setVisibility(Component.VISIBLE);
        resultMsgText.setText("");
        senDataToRemote();
        startTimer();
    }

    private void senDataToRemote() {
        if (remoteObject != null && proxy != null) {
            try {
                proxy.senDataToRemote(MathRemoteProxy.REQUEST_SEND_DATA);
            } catch (RemoteException e) {
                LogUtil.info("tag001", "senDataToRemote RemoteException");
                LogUtil.info(TAG, "processEvent RemoteException");
            }
        } else {
            LogUtil.info("tag001", "remoteObject == null || proxy == null");
        }
        checkShowMsg();
    }

    private void checkShowMsg() {
        myClickNumText.setText(myclickNum + "");
        otherClickNumText.setText(otherClickNum + "");
    }

    /**
     * Initialize and connect the device
     *
     * @param intent intent
     */
    private void initAndConnectDevice(Intent intent) {
        // Page initialization
        context = ClickGameSlice.this;
        String remoteDeviceId = intent.getStringParam(CommonData.KEY_REMOTE_DEVICEID);
        isLocal = intent.getBooleanParam(CommonData.KEY_IS_LOCAL, false);
        if (findComponentById(ResourceTable.Id_text_title) instanceof Text) {
            Text textTitle = (Text) findComponentById(ResourceTable.Id_text_title);
            textTitle.setText(isLocal ? "本地端" : "远程端");
        }

        // Connect to remote service
        if (!remoteDeviceId.isEmpty()) {
            connectRemotePa(remoteDeviceId);
        } else {
            LogUtil.info(TAG, "localDeviceId is null");
        }
    }

    private void connectRemotePa(String deviceId) {
        if (!deviceId.isEmpty()) {
            Intent connectPaIntent = new Intent();
            Operation operation = new Intent.OperationBuilder().withDeviceId(deviceId)
                    .withBundleName(getBundleName())
                    .withAbilityName(CommonData.CLICKGAME_SERVICE_NAME)
                    .withFlags(Intent.FLAG_ABILITYSLICE_MULTI_DEVICE)
                    .build();
            connectPaIntent.setOperation(operation);

            IAbilityConnection conn = new IAbilityConnection() {
                @Override
                public void onAbilityConnectDone(ElementName elementName, IRemoteObject remote, int resultCode) {
                    LogUtil.info(TAG, "onAbilityConnectDone......");
                    LogUtil.info("tag001", "onAbilityConnectDone......");
                    connectAbility(elementName, remote, resultCode);
                    hasPaConnectDone = true;
                }

                @Override
                public void onAbilityDisconnectDone(ElementName elementName, int resultCode) {
                    LogUtil.info(TAG, "onAbilityDisconnectDone......");
                    LogUtil.info("tag001", "onAbilityDisconnectDone......");
                    disconnectAbility(this);
                    hasPaConnectDone = false;
                }
            };

            context.connectAbility(connectPaIntent, conn);
        }
    }

    private void connectAbility(ElementName elementName, IRemoteObject remote, int resultCode) {
        remoteObject = remote;
        proxy = new MathRemoteProxy(remote);
        LogUtil.info(TAG, "connectRemoteAbility done connected to local service");
    }

    private void showMessage(String msg) {
        ToastDialog toastDialog = new ToastDialog(this);
        toastDialog.setText(msg);
        toastDialog.setAlignment(LayoutAlignment.CENTER);
        toastDialog.show();
    }

    @Override
    public void onActive() {
        super.onActive();
    }

    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }

    @Override
    protected void onStop() {
        super.onStop();
        unSubscribe();
        stopTimer();
    }

    private void subscribe() {
        MatchingSkills matchingSkills = new MatchingSkills();
        matchingSkills.addEvent(CommonData.CLICKGAME_EVENT);
        matchingSkills.addEvent(CommonEventSupport.COMMON_EVENT_SCREEN_ON);
        CommonEventSubscribeInfo subscribeInfo = new CommonEventSubscribeInfo(matchingSkills);
        subscriber = new MyCommonEventSubscriber(subscribeInfo);
        try {
            CommonEventManager.subscribeCommonEvent(subscriber);
        } catch (RemoteException e) {
            LogUtil.error("", "subscribeCommonEvent occur exception.");
        }
    }

    private void unSubscribe() {
        try {
            CommonEventManager.unsubscribeCommonEvent(subscriber);
        } catch (RemoteException e) {
            LogUtil.error(TAG, "unSubscribe Exception");
        }
    }

    /**
     * Establish a remote connection
     */
    class MathRemoteProxy implements IRemoteBroker {
        private static final int ERR_OK = 0;

        private static final int REQUEST_START_ABILITY = 1;

        private static final int REQUEST_SEND_DATA = 2;

        private final IRemoteObject remote;

        MathRemoteProxy(IRemoteObject remote) {
            this.remote = remote;
        }

        @Override
        public IRemoteObject asObject() {
            return remote;
        }

        private synchronized void senDataToRemote(int requestType) throws RemoteException {
            LogUtil.info(TAG, "send data to local draw service");
            MessageParcel data = MessageParcel.obtain();
            MessageParcel reply = MessageParcel.obtain();
            MessageOption option = new MessageOption(MessageOption.TF_SYNC);
            try {
                LogUtil.info("tag001", "senDataToRemote,status:" + status + ",myclickNum:" + myclickNum + ",currentTime:" + currentTime);
                data.writeInt(status);
                status = 0;
                data.writeInt(myclickNum);
                remote.sendRequest(requestType, data, reply, option);
                int ec = reply.readInt();
                if (ec != ERR_OK) {
                    LogUtil.error(TAG, "RemoteException:");
                }
            } catch (RemoteException e) {
                LogUtil.error(TAG, "RemoteException:");
            } finally {
                data.reclaim();
                reply.reclaim();
            }
        }
    }

    /**
     * MyCommonEventSubscriber
     */
    class MyCommonEventSubscriber extends CommonEventSubscriber {
        MyCommonEventSubscriber(CommonEventSubscribeInfo info) {
            super(info);
        }

        @Override
        public void onReceiveEvent(CommonEventData commonEventData) {
            Intent intent = commonEventData.getIntent();
            int status = intent.getIntParam(CommonData.KEY_STATUS, 0);
            otherClickNum = intent.getIntParam(CommonData.KEY_CLICK_NUM, 0);
            if (status == 1) {
                otherEnd = false;
                myclickNum = 0;
                otherClickNum = 0;
                currentTime = MAX_TIME;
                clickBtn.setVisibility(Component.VISIBLE);
                resultMsgText.setText("");
                startTimer();
            } else if (status == 2) {
                //对方结束
                otherEnd = true;
                checkShowResult();
            }
            checkShowMsg();
            LogUtil.info(TAG, "onReceiveEvent.....");
        }
    }
}
